package com.wchen.gdoc.generate.resource.analysis;

import com.sun.javadoc.ParameterizedType;
import com.sun.javadoc.Type;
import com.sun.javadoc.TypeVariable;
import com.wchen.gdoc.generate.config.ApplicationConfigProvide;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 *
 * 用于泛型处理
 *
 * @author wchen
 * @since
 **/
public class AbsGenericAnalysis extends AbsParentAnalysis {
    public static LinkedList<Map<String, Type>> genericLink = new LinkedList();

    /**
     * 提取泛型
     * @param docType
     */
    protected Map<String, Type> extractGeneric(Type docType) {
        TypeVariable[] typeVariables = docType.asClassDoc().typeParameters();
        if(typeVariables == null || typeVariables.length == 0) {
            LOGGER.info(String.format("%s no generic ...", docType.qualifiedTypeName()));
            return new HashMap<>();
        }

        ParameterizedType parameterizedType= docType.asParameterizedType();
        Type[] types = parameterizedType.typeArguments();

        Map<String, Type> typeNode = new HashMap<>();
        for (int i=0; i<typeVariables.length; i++) {
            String typeVariableName = typeVariables[i].qualifiedTypeName();
            if(i < types.length) {
                Type typeVariable = types[i];
                typeNode.put(typeVariableName, typeVariable);
            }
        }
        genericLink.addLast(typeNode);
        return typeNode;
    }

    /**
     * 移除最后个节点
     */
    protected void removeTypeNode() {
        genericLink.pollLast();
    }

    /**
     * 获取当前的泛型map
     */
    protected Map<String, Type> getCurrentGenericMap() {
        return genericLink.peekLast();
    }

    /**
     * 计算泛型最终类型
     *
     * @param docType
     * @return
     */
    protected Type calculateType(Type docType) {
        Map<String, Type> mappingTypeMap = getCurrentGenericMap();
        if(mappingTypeMap == null) {
            return docType;
        }

        //直接是泛型
        String qualifiedTypeName = docType.qualifiedTypeName();
        if(!qualifiedTypeName.contains(".")){
            return mappingTypeMap.get(qualifiedTypeName) == null ? docType : mappingTypeMap.get(qualifiedTypeName);
        }
        //class<T>
        Type genericType = super.extractGenericType(docType);
        if(genericType == null) {
            return docType;
        }
        return mappingTypeMap.get(genericType.qualifiedTypeName()) == null ? genericType : mappingTypeMap.get(genericType.qualifiedTypeName());
    }

}
